package cn.udrm.water.base.v1.waterdelivery.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.udrm.water.base.v1.commons.models.PageModel;
import cn.udrm.water.base.v1.commons.models.ZTreeNodeVo;
import cn.udrm.water.base.v1.waterdelivery.dto.CanalSystemDto;
import cn.udrm.water.base.v1.waterdelivery.dto.CanalSystemDtoMapper;
import cn.udrm.water.base.v1.waterdelivery.dto.CanalSystemSectionDto;
import cn.udrm.water.base.v1.waterdelivery.dto.CanalSystemSectionDtoMapper;
import cn.udrm.water.base.v1.waterdelivery.dto.DropDto;
import cn.udrm.water.base.v1.waterdelivery.dto.DropDtoMapper;
import cn.udrm.water.base.v1.waterdelivery.dto.InvertedSiphonDto;
import cn.udrm.water.base.v1.waterdelivery.dto.InvertedSiphonDtoMapper;
import cn.udrm.water.base.v1.waterdelivery.dto.PumpingStationDto;
import cn.udrm.water.base.v1.waterdelivery.dto.PumpingStationDtoMapper;
import cn.udrm.water.base.v1.waterdelivery.dto.SluiceDto;
import cn.udrm.water.base.v1.waterdelivery.dto.SluiceDtoMapper;
import cn.udrm.water.base.v1.waterdelivery.dto.SteepSlopeDto;
import cn.udrm.water.base.v1.waterdelivery.dto.SteepSlopeDtoMapper;
import cn.udrm.water.base.v1.waterdelivery.dto.TunnelDto;
import cn.udrm.water.base.v1.waterdelivery.dto.TunnelDtoMapper;
import cn.udrm.water.base.v1.waterdelivery.entities.CanalSystem;
import cn.udrm.water.base.v1.waterdelivery.entities.CanalSystemExt;
import cn.udrm.water.base.v1.waterdelivery.entities.CanalSystemSection;
import cn.udrm.water.base.v1.waterdelivery.entities.Drop;
import cn.udrm.water.base.v1.waterdelivery.entities.InvertedSiphon;
import cn.udrm.water.base.v1.waterdelivery.entities.PumpingStation;
import cn.udrm.water.base.v1.waterdelivery.entities.Sluice;
import cn.udrm.water.base.v1.waterdelivery.entities.SteepSlope;
import cn.udrm.water.base.v1.waterdelivery.entities.Tunnel;
import cn.udrm.water.base.v1.waterdelivery.repository.CanalSystemExtRepository;
import cn.udrm.water.base.v1.waterdelivery.repository.CanalSystemRepository;
import cn.udrm.water.base.v1.waterdistribute.dto.WaterGateDto;
import cn.udrm.water.base.v1.waterdistribute.dto.WaterGateDtoMapper;
import cn.udrm.water.base.v1.waterdistribute.entities.WaterGate;
import cn.udrm.water.base.v1.waterdistribute.service.WaterGateService;

@Service
@Transactional(readOnly=true)
public class CanalSystemService {
	@Autowired
	private CanalSystemRepository canalSystemRepository;
	@Autowired
	private WaterGateService waterGateService;
	@Autowired
	private CanalSystemDtoMapper canalSystemDtoMapper;
	@Autowired
	private CanalSystemExtRepository canalSystemExtRepository;
	@Autowired
	private WaterGateDtoMapper waterGateDtoMapper;
	@Autowired
	private CanalSystemSectionDtoMapper canalSystemSectionDtoMapper;
	@Autowired
	private DropDtoMapper dropDtoMapper;
	@Autowired
	private InvertedSiphonDtoMapper invertedSiphonDtoMapper;
	@Autowired
	private PumpingStationDtoMapper pumpingStationDtoMapper;
	@Autowired
	private SluiceDtoMapper sluiceDtoMapper;
	@Autowired
	private SteepSlopeDtoMapper steepSlopeDtoMapper;
	@Autowired
	private TunnelDtoMapper tunnelDtoMapper;
	
	public List<ZTreeNodeVo> getCanalSystemZtree() {
		List<CanalSystem> list = canalSystemRepository.findAllSelf();
		List<CanalSystemDto> from = canalSystemDtoMapper.from(list);
		List<ZTreeNodeVo> treeNodeVos = new ArrayList<ZTreeNodeVo>(from.size());
		from.forEach((canalSystemDto) -> {
			ZTreeNodeVo zTreeNodeVo = new ZTreeNodeVo(canalSystemDto.getId(), canalSystemDto.getName(), canalSystemDto.getParentGuid());
			treeNodeVos.add(zTreeNodeVo);
		});
		return treeNodeVos;
	}
	
	/**
	 * 分页条件查询
	 * @param pageNumberStr
	 * @param pageSizeStr
	 * @param waterGateSearch
	 * @param sortField
	 * @param sortType
	 * @return
	 */
	public PageModel<CanalSystemDto> getPageByConditions(String pageNumberStr, String pageSizeStr, final CanalSystemDto canalSystemSearch
			, String sortField, String sortType) {
		int number = 0,
			size = 0;
		try {
			number = Integer.parseInt(pageNumberStr);
		} catch (Exception e) {}
		try {
			size = Integer.parseInt(pageSizeStr);
		} catch (Exception e) {}
		size = size == 0 ? 10 : size;
		Sort sort = null;
		if (!StringUtils.isEmpty(sortField)) {
			try {
				sort = new Sort(StringUtils.isEmpty(sortType) ? Direction.ASC : (sortType.equals("ASC")) ? Direction.ASC : Direction.DESC, sortField);
			} catch (Exception e) {}
		} else {
			sort = new Sort(Direction.ASC, "createDate");
		}
		Pageable pageable = PageRequest.of(number, size, sort);
		Specification<CanalSystem> specification = new Specification<CanalSystem>() {
			private static final long serialVersionUID = 1L;

			@Override
			public Predicate toPredicate(Root<CanalSystem> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				List<Predicate> predicates = new ArrayList<>();
				
				if (predicates.size() == 0) {
					return null;
				}
				Predicate predicateArr[] = new Predicate[predicates.size()];
				return cb.and(predicates.toArray(predicateArr));
			}
		};
		Page<CanalSystem> page = canalSystemRepository.findAll(specification, pageable);
		List<CanalSystem> content = page.getContent();
		/*for (CanalSystem canalSystem : content) {
			canalSystem = canalSystem.getEntitySelf(canalSystem);
		}*/
		List<CanalSystemDto> dtos = canalSystemDtoMapper.from(content);
		PageModel<CanalSystemDto> pageModel = new PageModel<CanalSystemDto>(page.getSize(), page.getNumber(), page.getTotalElements(), dtos);
		return pageModel;
	}

	public CanalSystemDto getWithWaterGates(String id) {
		CanalSystem canalSystem = canalSystemRepository.findWithWaterGatesById(id);
		if (canalSystem == null) {
			return null;
		}
		CanalSystemDto canalSystemDto = canalSystemDtoMapper.from(canalSystem);
		/*
		 * 处理闸门
		 */
		List<WaterGate> waterGates = canalSystem.getWaterGates();
		if (waterGates != null && waterGates.size() != 0) {
			List<WaterGateDto> list = waterGateDtoMapper.from(waterGates);
			canalSystemDto.setWaterGateDtos(list);
		}
		return canalSystemDto;
	}
	
	public CanalSystemDto getWithChildrens(String id) {
		CanalSystem canalSystem = canalSystemRepository.findChildrensById(id);
		if (canalSystem == null) {
			return null;
		}
		CanalSystemDto canalSystemDto = canalSystemDtoMapper.from(canalSystem);
		/*
		 * 处理子渠道
		 */
		List<CanalSystem> childrens = canalSystem.getChildrens();
		if (childrens != null && childrens.size() != 0) {
			List<CanalSystemDto> list = canalSystemDtoMapper.from(childrens);
			canalSystemDto.setChildrenCanalSystemDtos(list);
		}
		return canalSystemDto;
	}
	
	public CanalSystemDto getWithCanalSystemSections(String id) {
		CanalSystem canalSystem = canalSystemRepository.findWithCanalSystemSectionsById(id);
		if (canalSystem == null) {
			return null;
		}
		CanalSystemDto canalSystemDto = canalSystemDtoMapper.from(canalSystem);
		/*
		 * 处理断面
		 */
		List<CanalSystemSection> canalSystemSections = canalSystem.getCanalSystemSections();
		if (canalSystemSections != null && canalSystemSections.size() != 0) {
			List<CanalSystemSectionDto> list = canalSystemSectionDtoMapper.from(canalSystemSections);
			canalSystemDto.setCanalSystemSectionDtos(list);
		}
		return canalSystemDto;
	}
	
	public CanalSystemDto getWithDrops(String id) {
		CanalSystem canalSystem = canalSystemRepository.findWithDropsById(id);
		if (canalSystem == null) {
			return null;
		}
		CanalSystemDto canalSystemDto = canalSystemDtoMapper.from(canalSystem);
		/*
		 * 处理跌水
		 */
		List<Drop> drops = canalSystem.getDrops();
		if (drops != null && drops.size() != 0) {
			List<DropDto> list = dropDtoMapper.from(drops);
			canalSystemDto.setDropDtos(list);
		}
		return canalSystemDto;
	}
	
	public CanalSystemDto getWithInvertedSiphons(String id) {
		CanalSystem canalSystem = canalSystemRepository.findWithInvertedSiphonsById(id);
		if (canalSystem == null) {
			return null;
		}
		CanalSystemDto canalSystemDto = canalSystemDtoMapper.from(canalSystem);
		/*
		 * 处理倒虹吸
		 */
		List<InvertedSiphon> invertedSiphons = canalSystem.getInvertedSiphons();
		if (invertedSiphons != null && invertedSiphons.size() != 0) {
			List<InvertedSiphonDto> list = invertedSiphonDtoMapper.from(invertedSiphons);
			canalSystemDto.setInvertedSiphonDtos(list);
		}
		return canalSystemDto;
	}
	
	public CanalSystemDto getWithPumpingStations(String id) {
		CanalSystem canalSystem = canalSystemRepository.findWithPumpingStationsById(id);
		if (canalSystem == null) {
			return null;
		}
		CanalSystemDto canalSystemDto = canalSystemDtoMapper.from(canalSystem);
		/*
		 * 处理扬水站
		 */
		List<PumpingStation> pumpingStations = canalSystem.getPumpingStations();
		if (pumpingStations != null && pumpingStations.size() != 0) {
			List<PumpingStationDto> list = pumpingStationDtoMapper.from(pumpingStations);
			canalSystemDto.setPumpingStationDtos(list);
		}
		return canalSystemDto;
	}
	
	public CanalSystemDto getWithSluices(String id) {
		CanalSystem canalSystem = canalSystemRepository.findWithSluicesById(id);
		if (canalSystem == null) {
			return null;
		}
		CanalSystemDto canalSystemDto = canalSystemDtoMapper.from(canalSystem);
		/*
		 * 处理渡槽
		 */
		List<Sluice> sluices = canalSystem.getSluices();
		if (sluices != null && sluices.size() != 0) {
			List<SluiceDto> list = sluiceDtoMapper.from(sluices);
			canalSystemDto.setSluiceDtos(list);
		}
		return canalSystemDto;
	}
	
	public CanalSystemDto getWithSteepSlopes(String id) {
		CanalSystem canalSystem = canalSystemRepository.findWithSteepSlopesById(id);
		if (canalSystem == null) {
			return null;
		}
		CanalSystemDto canalSystemDto = canalSystemDtoMapper.from(canalSystem);
		/*
		 * 处理陡坡
		 */
		List<SteepSlope> steepSlopes = canalSystem.getSteepSlopes();
		if (steepSlopes != null && steepSlopes.size() != 0) {
			List<SteepSlopeDto> list = steepSlopeDtoMapper.from(steepSlopes);
			canalSystemDto.setSteepSlopeDtos(list);
		}
		return canalSystemDto;
	}
	
	public CanalSystemDto getWithTunnels(String id) {
		CanalSystem canalSystem = canalSystemRepository.findWithTunnelsById(id);
		if (canalSystem == null) {
			return null;
		}
		CanalSystemDto canalSystemDto = canalSystemDtoMapper.from(canalSystem);
		/*
		 * 处理隧洞
		 */
		List<Tunnel> tunnels = canalSystem.getTunnels();
		if (tunnels != null && tunnels.size() != 0) {
			List<TunnelDto> list = tunnelDtoMapper.from(tunnels);
			canalSystemDto.setTunnelDtos(list);
		}
		return canalSystemDto;
	}
	
	public CanalSystemDto getSelfById(String id) {
		CanalSystem canalSystem = canalSystemRepository.findSelfById(id);
		CanalSystemDto canalSystemDto = canalSystemDtoMapper.from(canalSystem);
		return canalSystemDto;
	}
	
	@Transactional(readOnly=false)
	public CanalSystemDto save(CanalSystemDto canalSystemDto) {
		CanalSystem canalSystem = canalSystemDtoMapper.fromCanalSystemDto(canalSystemDto);
		canalSystem.setCreateDate(new Date());
		canalSystem.setId(null);
		String canalSystemExtGuid = canalSystemDto.getCanalSystemExtGuid();
		CanalSystemExt canalSystemExtTtemp = null;
		if (StringUtils.isNotBlank(canalSystemExtGuid)) {
			canalSystemExtTtemp = canalSystemExtRepository.getOne(canalSystemExtGuid);
		}
		/*
		 * 设置父对象
		 */
		CanalSystem parent = null;
		String parentGuid = canalSystemDto.getParentGuid();
		if (StringUtils.isNotBlank(parentGuid)) {
			parent = canalSystemRepository.findSelfById(parentGuid);
		}
		if (parent != null && StringUtils.isNotBlank(parent.getId())) {
			canalSystem.setParent(parent);
		}
		canalSystem = canalSystemRepository.saveAndFlush(canalSystem);
		/*
		 * 保存扩展表
		 */
		if (canalSystemExtTtemp == null) {
			canalSystemExtTtemp = new CanalSystemExt();
		} 
		canalSystemExtTtemp.setCanalSystem(new CanalSystem(canalSystem.getId()));
		canalSystemExtTtemp.setManagerUnitGuid(canalSystemDto.getCanalSystemExtManagerUnitGuid());
		canalSystemExtTtemp.setManagerUnitName(canalSystemDto.getCanalSystemExtManagerUnitName());
		canalSystemExtRepository.saveAndFlush(canalSystemExtTtemp);
		CanalSystemDto dto = canalSystemDtoMapper.from(canalSystem);
		return dto;
	}
	@Transactional(readOnly=false)
	public CanalSystemDto update(CanalSystemDto canalSystemDto) {
		CanalSystem canalSystem = canalSystemDtoMapper.fromCanalSystemDto(canalSystemDto);
		String canalSystemExtGuid = canalSystemDto.getCanalSystemExtGuid();
		CanalSystemExt canalSystemExtTtemp = null;
		if (StringUtils.isNotBlank(canalSystemExtGuid)) {
			canalSystemExtTtemp = canalSystemExtRepository.getOne(canalSystemExtGuid);
		}
		/*
		 * 设置父对象
		 */
		CanalSystem parent = null;
		String parentGuid = canalSystemDto.getParentGuid();
		if (StringUtils.isNotBlank(parentGuid)) {
			parent = canalSystemRepository.findSelfById(parentGuid);
		}
		if (parent != null && StringUtils.isNotBlank(parent.getId())) {
			canalSystem.setParent(parent);
		}
		canalSystem = canalSystemRepository.saveAndFlush(canalSystem);
		/*
		 * 更新扩展表
		 */
		if (canalSystemExtTtemp == null) {
			canalSystemExtTtemp = new CanalSystemExt();
		}
		canalSystemExtTtemp.setCanalSystem(new CanalSystem(canalSystem.getId()));
		canalSystemExtTtemp.setManagerUnitGuid(canalSystemDto.getCanalSystemExtManagerUnitGuid());
		canalSystemExtTtemp.setManagerUnitName(canalSystemDto.getCanalSystemExtManagerUnitName());
		canalSystemExtRepository.saveAndFlush(canalSystemExtTtemp);
		CanalSystemDto dto = canalSystemDtoMapper.from(canalSystem);
		return dto;
	}
	
	/**
	 * 删除所有信息, 包括其级联的所有实体
	 * @param ids
	 */
	@Transactional(readOnly=false)
	public void deleteAll(String[] ids) {
		if (ids == null || ids.length == 0) {
			return;
		}
		List<CanalSystem> canalSystems = new ArrayList<CanalSystem>();
		for (String id : ids) {
			canalSystems.add(new CanalSystem(id));
		}
		this.deleteAll(canalSystems);
	}
	
	/**
	 * 该方法不能随意调用, 会引起整个关联数据的删除
	 * @param iterable
	 */
	@Transactional(readOnly=false)
	private void deleteAll(Iterable<CanalSystem> iterable) {
		if (iterable == null || iterable.iterator() == null) {
			return;
		}
		Iterator<CanalSystem> iterator = iterable.iterator();
		while (iterator.hasNext()) {
			CanalSystem canalSystem = iterator.next();
			canalSystem = canalSystemRepository.findSelfById(canalSystem.getId());
			List<WaterGate> waterGates = canalSystem.getWaterGates();
			waterGateService.deleteAll(waterGates);
			List<CanalSystem> childrens = canalSystem.getChildrens();
			this.deleteAll(childrens);
			canalSystemRepository.delete(canalSystem);
		}
	}
	
	@Transactional(readOnly=false)
	public void deleteAllSelf(String[] ids) {
		if (ids == null || ids.length == 0) {
			return;
		}
		for (String id : ids) {
			canalSystemRepository.deleteById(id);
		}
	}
	
}
